package apiexample.transform.descriptionextraction;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import util.StringDealer;

import apiexample.transform.datastructure.UsageExample;

import com.apiexample.server.entity.DescriptionEntity;

import dao.entity.SegmentEntity;

public class EnhancedDescriptionExtraction implements DescriptionExtraction {

	@Override
	public ArrayList<DescriptionEntity> getFollowingDescriptionsOfCode(ArrayList<SegmentEntity> segments,
			UsageExample example, int indexOfCode, int maxLen) {
		long time_1 = System.currentTimeMillis();
		// the index of this code segment in the page
		int i = indexOfCode;
		ArrayList<DescriptionEntity> result = new ArrayList<DescriptionEntity>();
		int textLength = 0;
		softBreakTagCount = 0;// return to initial
		for (int j = 1;; j++) {
			int des_index = i + j;
			if (des_index < segments.size()) {
				SegmentEntity thisSegment = segments.get(des_index);
				// stop condition 4: encounter code segment
				if (thisSegment.getType() == SegmentEntity.NON_CODE_SEGMENT) {
					String content = thisSegment.getContent();
					// if the length has not reached the minmum requirement,
					// continue merge. otherwise, break;
					if (textLength > maxLen) {
						break;
					}
					if (thisSegment.getType() == SegmentEntity.SPAM_SEGMENT) {
						break;
					}
					if (isContentBreak(thisSegment)) {
						// stop condition 3: encounter content break tag
						// do not add the content of break to the text
						break;
					}

					// index of preceding text is positive 3 2 1; index of following text is negative -1 -2 -3
					// DescriptionEntity desEntity = new DescriptionEntity(-1, -1*j,
					// -1, KeywordsHighLighter.hightLight(content, example.declaredElementNames,
					// example.referencedElementNames, DELIMITERS, true, BEGINTAG, ENDTAG));
					DescriptionEntity desEntity = new DescriptionEntity(-1, -1 * j, -1, content);
					result.add(desEntity);

					textLength += StringDealer.countTokens(content);

				} else {
					break;
				}
			} else {
				break;
			}
		}

		if (!shouldShowFollowingDes(result, example)) {
			return new ArrayList<DescriptionEntity>();
		} else {
			System.out.println("Should show following descriptions for example:" + example.getEntity().getId());
			return result;
		}
	}

	@Override
	public ArrayList<DescriptionEntity> getPrecedingDescriptionsOfCode(ArrayList<SegmentEntity> segments,
			UsageExample example, int indexOfCode, int maxLen) {
		long time_1 = System.currentTimeMillis();
		// the index of this code segment in the page
		int i = indexOfCode;
		ArrayList<DescriptionEntity> result = new ArrayList<DescriptionEntity>();
		int textLength = 0;
		softBreakTagCount = 0;// return to initial
		for (int j = 1;; j++) {
			int des_index = i - j;
			if (des_index >= 0) {
				SegmentEntity thisSegment = segments.get(des_index);
				// stop condition 4: encounter code segment
				if (thisSegment.getType() == SegmentEntity.NON_CODE_SEGMENT) {

					// stop condition 1: if the length has not reached the minmum requirement,
					// continue merge. otherwise, break;
					if (textLength > maxLen) {
						break;
					}

					// stop condition 2: spam content
					if (thisSegment.getType() == SegmentEntity.SPAM_SEGMENT) {
						break;
					}

					String content = thisSegment.getContent();
					// index of preceding text is positive 3 2 1; index of following text is negative -1 -2 -3

					DescriptionEntity desEntity = new DescriptionEntity(-1, j, -1, content);
					result.add(desEntity);
					textLength += StringDealer.countTokens(content);

					if (isContentBreak(thisSegment)) {
						// stop condition 3: encounter content break tag
						// add the content of break to the text
						break;
					}

				} else {
					break;
				}
			} else {
				break;
			}
		}
		System.out.println("[INFO]Get descirption time cost:" + (System.currentTimeMillis() - time_1));
		return result;
	}

	/**
	 * Feature 1: whether the segments mention the programming elements (class, methods, fields, variables) declared by
	 * the code? (YY) public class CopyLines {… Invoking readLine returns a line of text with the line. CopyLines
	 * outputs each line using println, which appends the line terminator for the current operating system. This might
	 * not be the same line terminator that was used in the input file. Feature 2: whether the segments mention the
	 * programming elements (class, methods, fields, variables) used by the code
	 * 
	 * Feature 3: whether the segments mention parameters of the code? () FileReader fro = new FileReader( "myFile.txt"
	 * ); … myFile.txt is on the same drive in directory where you… Feature 4: whether the segments discuss the behavior
	 * of the code? (output, input, result) Here is the output of Root:
	 * 
	 * The square root of 2 is 1.4142135623730951. The square root of 5 is 2.23606797749979. Feature 5: Contain some
	 * clue terms, such as “This program”, “The above program”, “This simple class”
	 * 
	 * @param content
	 * @param example
	 * @return
	 */
	public boolean shouldShowFollowingDes(ArrayList<DescriptionEntity> content, UsageExample example) {
		int count = 0;
		for (DescriptionEntity des : content) {
			if (des.getContent() == null) {
				continue;
			}
			StringTokenizer tokenizer = new StringTokenizer(des.getContent());
			while (tokenizer.hasMoreTokens()) {
				String token = tokenizer.nextToken();
				if (example.declaredMethodNames.contains(token)) {
					count++;
					continue;
				}
				if (example.declaredMethodNames.contains(token)) {
					count++;
					continue;
				}
				if (example.actualArgs.contains(token)) {
					count++;
					continue;
				}
				if (outputSymbols.contains(token)) {
					count++;
					continue;
				}
			}
		}
		if (count >= 1)
			return true;
		else
			return false;
	}

	/*
	 * The following is used for judge whether the segment being processed is a content break
	 */
	public static String[] hardContentBreakTag = { "h1", "h2", "h3", "h4", "h5", "h6", "hr", "ol", "ul" };
	public static String[] softContentBreakTag = { "table", "div", "tr" };
	public static HashSet<String> outputSymbols = new HashSet<String>();
	static {
		outputSymbols.add("output");
		outputSymbols.add("print");
		outputSymbols.add("result");
		outputSymbols.add("results");
		outputSymbols.add("input");
	}
	private static int softBreakTagCount = 0;

	public static boolean isContentBreak(SegmentEntity segment) {
		StringBuffer hardBuffer = new StringBuffer();
		StringBuffer softBuffer = new StringBuffer();
		for (int i = 0; i < hardContentBreakTag.length; i++) {
			if (i != 0) {
				hardBuffer.append("|");
			}
			hardBuffer.append(hardContentBreakTag[i]);
		}
		for (int i = 0; i < softContentBreakTag.length; i++) {
			if (i != 0) {
				softBuffer.append("|");
			}
			softBuffer.append(softContentBreakTag[i]);
		}
		String hard_str_pattern = "(.*?)<(\\s*?)(" + hardBuffer.toString() + ")(.*?)>(.*?)";
		String soft_str_pattern = "(.*?)<(\\s*?)(" + softBuffer.toString() + ")(.*?)>(.*?)";

		// System.out.println(str_pattern);
		Pattern hard_pattern = Pattern.compile(hard_str_pattern, Pattern.CASE_INSENSITIVE);
		Matcher hard_matcher = hard_pattern.matcher(segment.getBegin_tag());
		if (hard_matcher.matches()) {
			System.out.println("[Content break]Hard content break match!" + segment.getPage_id() + " "
					+ segment.getBegin_tag());
			return true;
		}

		Pattern soft_pattern = Pattern.compile(soft_str_pattern, Pattern.CASE_INSENSITIVE);
		Matcher soft_matcher = soft_pattern.matcher(segment.getBegin_tag());
		// System.out.println(hard_matcher.matches());
		// System.out.println(soft_matcher.matches());
		while (soft_matcher.find()) {
			softBreakTagCount++;
		}
		if (softBreakTagCount > 2) {
			System.out.println("[Content break]Soft content break match!" + segment.getPage_id() + " "
					+ segment.getBegin_tag());
			return true;
		}
		return false;
	}
	public static void main(String[] args){
		String begin_tag = "<ul></div></div></div></div><table><table><div id=\"mainbody\">";
		SegmentEntity segment = new SegmentEntity(0, 0, 0, SegmentEntity.NON_CODE_SEGMENT, 0, begin_tag, "", "", "");
		System.out.println(isContentBreak(segment));
	}
}
